#include "drv_uart.h"

tx_queue_t tx_queue[MAXQSIZE];
tx_queue_data_t tx_queue_buff[MAXQSIZE][MAXQSIZE];
static tx_queue_data_t tx_queue_data;

struct termios oterm_attr;
struct itimerval tick;

int baudflag_arr[] = {
    B921600, B460800, B230400, B115200, B57600, B38400,
    B19200,  B9600,   B4800,   B2400,   B1800,  B1200,
    B600,    B300,    B150,    B110,    B75,    B50
};

int speed_arr[] = {
    921600,  460800,  230400,  115200,  57600,  38400,
    19200,   9600,    4800,    2400,    1800,   1200,
    600,     300,     150,     110,     75,     50
};

int speed_to_flag(int speed)
{
    int i;

    for (i = 0;  i < sizeof(speed_arr)/sizeof(int);  i++) {
        if (speed == speed_arr[i]) {
            return baudflag_arr[i];
        }
    }

    fprintf(stderr, "Unsupported baudrate, use 9600 instead!\n");
    return B9600;
}

int setup_port(int fd, int baud, int databits, int parity, int stopbits)
{
    struct termios term_attr;

    if (tcgetattr(fd, &term_attr) < 0) {
        return -1;
    }

    memcpy(&oterm_attr, &term_attr, sizeof(struct termios));

    term_attr.c_iflag &= ~(INLCR | IGNCR | ICRNL | ISTRIP | IXON);
    term_attr.c_oflag &= ~(OPOST | ONLCR | OCRNL);
    term_attr.c_lflag &= ~(ISIG | ECHO | ICANON | NOFLSH);
    term_attr.c_cflag &= ~CBAUD;
    term_attr.c_cflag |= CREAD | speed_to_flag(baud);

    term_attr.c_cflag &= ~(CSIZE);
    switch (databits) {
        case 5:
            term_attr.c_cflag |= CS5;
            break;

        case 6:
            term_attr.c_cflag |= CS6;
            break;

        case 7:
            term_attr.c_cflag |= CS7;
            break;

        case 8:
        default:
            term_attr.c_cflag |= CS8;
            break;
    }

    switch (parity) {
        case 1://奇数
            term_attr.c_cflag |= (PARENB | PARODD);
            break;

        case 2://偶数
            term_attr.c_cflag |= PARENB;
            term_attr.c_cflag &= ~(PARODD);
            break;

        case 0:
        default:
            term_attr.c_cflag &= ~(PARENB);
            break;
    }

    switch (stopbits) {
        case 2:
            term_attr.c_cflag |= CSTOPB;
            break;


        case 1:
        default:
            term_attr.c_cflag &= ~CSTOPB;
            break;
    }

    term_attr.c_cc[VMIN] = 1;
    term_attr.c_cc[VTIME] = 0;

    if (tcsetattr(fd, TCSANOW, &term_attr) < 0) {
        return -1;
    }

    if (tcflush(fd, TCIOFLUSH) < 0) {
        return -1;
    }

    return 0;
}

int read_data(int fd, void *buf, int len)
{
    int count;
    int ret;


    ret = 0;
    count = 0;


    //while (len > 0) {


    ret = read(fd, (char*)buf + count, len);
    if (ret < 1) {
        return 0;
        //fprintf(stderr, "Read error %s\n", strerror(errno));
        //break;
    }


    count += ret;
    len = len - ret;


    //}


    *((char*)buf + count) = 0;
    return count;
}

int write_data(int fd, void *buf, int len)
{
    int count;
    int ret;


    ret = 0;
    count = 0;


    while (len > 0) {


        ret = write(fd, (char*)buf + count, len);
        if (ret < 1) {
            fprintf(stderr, "Write error %s\n", strerror(errno));
            break;
        }


        count += ret;
        len = len - ret;
    }


    return count;
}

int reset_port(int fd)
{
    if (ioctl(fd, TCSETAW, &oterm_attr) < 0) {
        return -1;
    }

    return 0;
}

//================队列初始化==========
int tx_queue_init(tx_queue_t *q, tx_queue_data_t *b) 
{
	//构造一个空队列Q
	q->base = b;
	if (!q->base) return -1;//存储分配失败
	q->front = q->rear = 0;
	return 1;
}


//================入队================================
int tx_queue_in(tx_queue_t *q, tx_queue_data_t e) 
{
	//插入元素e为Q的新的队尾元素
	if ((q->rear + 1) % MAXQSIZE == q->front)return 0;//队列满`
	q->base[q->rear] = e;
	q->rear = (q->rear + 1) % MAXQSIZE;//重新设置队尾指针
	return 1;
}


//===============出队=================================
int tx_queue_out(tx_queue_t *q, tx_queue_data_t *e) 
{
	//若队列不空，则删除Q的对头元素，用e返回其值
	if (q->front == q->rear)return 0;//队空
	*e = q->base[q->front];
	q->front = (q->front + 1) % MAXQSIZE;
	return 1;
}
